//// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
//// Copyright (C) 2010  Winch Gate Property Limited
////
//// This program is free software: you can redistribute it and/or modify
//// it under the terms of the GNU Affero General Public License as
//// published by the Free Software Foundation, either version 3 of the
//// License, or (at your option) any later version.
////
//// This program is distributed in the hope that it will be useful,
//// but WITHOUT ANY WARRANTY; without even the implied warranty of
//// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//// GNU Affero General Public License for more details.
////
//// You should have received a copy of the GNU Affero General Public License
//// along with this program.  If not, see <http://www.gnu.org/licenses/>.
//
//#include "stdmisc.h"
//
//#include "nel/misc/bitmap.h"
//
//#include "nel/misc/stream.h"
//#include "nel/misc/file.h"
//#include "nel/misc/rgba.h"
//#include "nel/misc/dynloadlib.h"
//#include <png.h>
//#include <csetjmp>
//
//using namespace std;
//
//#ifdef DEBUG_NEW
//	#define new DEBUG_NEW
//#endif
//
//namespace NLMISC
//{
//
//static void readPNGData(png_structp png_ptr, png_bytep data, png_size_t length)
//{
//	IStream *stream = static_cast<IStream*>(png_get_io_ptr(png_ptr));
//	if (stream)
//		stream->serialBuffer((uint8*)data, (uint)length);
//}
//
//static void writePNGData(png_structp png_ptr, png_bytep data, png_size_t length)
//{
//	IStream *stream = static_cast<IStream*>(png_get_io_ptr(png_ptr));
//	if (stream)
//		stream->serialBuffer((uint8*)data, (uint)length);
//}
//
//static void setPNGWarning(png_struct * /* png_ptr */, const char* message)
//{
//	nlwarning(message);
//}
//
//static void setPNGError(png_struct *png_ptr, const char* message)
//{
//	setPNGWarning(png_ptr, message);
//
//	longjmp(png_jmpbuf(png_ptr), 1);
//}
//
///*-------------------------------------------------------------------*\
//							readPNG
//\*-------------------------------------------------------------------*/
//uint8 CBitmap::readPNG( NLMISC::IStream &f )
//{
//	if(!f.isReading()) return false;
//
//	// initialize the info header
//	png_struct *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, setPNGError, setPNGWarning);
//
//	if (png_ptr == NULL)
//	{
//		nlwarning("failed to create the png read struct");
//		return 0;
//	}
//
//	// allocate/initialize the memory for image information.
//	png_info *info_ptr = png_create_info_struct(png_ptr);
//
//	if (info_ptr == NULL)
//	{
//		png_destroy_read_struct(&png_ptr, NULL, NULL);
//		nlwarning("failed to create the png info struct");
//		return 0;
//	}
//
//	if (setjmp(png_jmpbuf(png_ptr)))
//	{
//		// free all of the memory associated with the png_ptr and info_ptr
//		png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
//		// if we get here, we had a problem reading the file
//		nlwarning("failed to setjump");
//		return 0;
//	}
//
//	// set the read function
//	png_set_read_fn(png_ptr, (void*)&f, readPNGData);
//
//	// set number of bit already read (in order to step back)
//	png_set_sig_bytes(png_ptr, 4);
//
//	// read header info and use it
//	png_read_info(png_ptr, info_ptr);
//
//	// get header infos
//	png_uint_32 width, height;
//	int iBitDepth, iColorType;
//	png_get_IHDR(png_ptr, info_ptr, &width, &height, &iBitDepth, &iColorType, NULL, NULL, NULL);
//
//	// expand images of all color-type and bit-depth to 3x8 bit RGB images
//	// let the library process things like alpha, transparency, background
//	double dGamma;
//
//	// make sure it will use 8 bits per channel
//	if (iBitDepth == 16)
//		png_set_strip_16(png_ptr);
//	else if (iBitDepth < 8)
//		png_set_packing(png_ptr);
//
//	// expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel
//	if (iBitDepth < 8 || iColorType == PNG_COLOR_TYPE_PALETTE || png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))
//		png_set_expand(png_ptr);
//
//	// if required set gamma conversion
//	if (png_get_gAMA(png_ptr, info_ptr, &dGamma))
//		png_set_gamma(png_ptr, (double) 2.2, dGamma);
//
//	// add alpha byte after each RGB triplet if it doesn't exist
//	png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
//
//	// after the transformations have been registered update info_ptr data
//	png_read_update_info(png_ptr, info_ptr);
//
//	// get again width, height and the new bit-depth and color-type
//	png_get_IHDR(png_ptr, info_ptr, &width, &height, &iBitDepth, &iColorType, NULL, NULL, NULL);
//
//	// at this point, the image must be converted to an 24bit image RGB
//
//	// rowbytes is the width x number of channels
//	uint32 rowbytes = (uint32)png_get_rowbytes(png_ptr, info_ptr);
//	uint32 srcChannels = png_get_channels(png_ptr, info_ptr);
//
//	// allocates buffer to copy image data
//	png_bytepp row_pointers = (png_bytepp)png_malloc(png_ptr, height * sizeof(png_bytep));
//
//	for (uint row = 0; row < height; row++)
//		row_pointers[row] = (png_bytep)png_malloc(png_ptr, rowbytes);
//
//	// effective read of the image
//	png_read_image(png_ptr, row_pointers);
//
//	// read rest of file, and get additional chunks in info_ptr
//	png_read_end(png_ptr, info_ptr);
//
//	uint32 dstChannels = 0, firstChannel = 0, lastChannel = 0;
//
//	if (iColorType == PNG_COLOR_TYPE_RGBA || iColorType == PNG_COLOR_TYPE_RGB || iColorType == PNG_COLOR_TYPE_PALETTE)
//	{
//		// get all channels
//		dstChannels = 4;
//		firstChannel = 0;
//		lastChannel = 3;
//		resize (width, height, RGBA);
//	}
//	else if (iColorType == PNG_COLOR_TYPE_GRAY)
//	{
//		// only get gray channel
//		dstChannels = 1;
//		firstChannel = 0;
//		lastChannel = 0;
//		resize (width, height, _LoadGrayscaleAsAlpha ? Alpha : Luminance);
//	}
//	else if (iColorType == PNG_COLOR_TYPE_GRAY_ALPHA)
//	{
//		// get gray and alpha channels
//		dstChannels = 2;
//		firstChannel = 0;
//		lastChannel = 1;
//		resize (width, height, AlphaLuminance);
//	}
//	else
//	{
//		png_error(png_ptr, "unknown iColorType");
//	}
//
//	for (uint32 y = 0; y < height; y++)
//	{
//		for (uint32 x = 0; x < width; x++)
//		{
//			uint32 dstOffset = y*width*dstChannels+x*dstChannels;
//			const uint32 srcOffset = x*srcChannels;
//
//			for (uint32 pix = firstChannel; pix <= lastChannel; pix++)
//				_Data[0][dstOffset++] = row_pointers[y][srcOffset+pix];
//		}
//	}
//
//	// free allocated memory to copy each rows
//	for (uint row = 0; row < height; row++)
//		png_free(png_ptr, row_pointers[row]);
//
//	// free allocated memory to copy the image
//	png_free(png_ptr, row_pointers);
//
//	// clean up after the read, and free any memory allocated
//	png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
//
//	//return the size of a pixel, either 8,24,32 bit
//	return uint8(dstChannels * iBitDepth);
//}
//
///*-------------------------------------------------------------------*\
//							writePNG
//\*-------------------------------------------------------------------*/
//bool CBitmap::writePNG( NLMISC::IStream &f, uint32 d)
//{
//	if(f.isReading()) return false;
//
//	if (PixelFormat > AlphaLuminance) return false;
//	if (!_Width || !_Height) return false;
//
//	if (d == 0) d = bitPerPixels[PixelFormat];
//
//	if (d!=32 && d!=24 && d!=16 && d!=8) return false;
//
//	// create image write structure
//	png_struct *png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, setPNGError, setPNGWarning);
//
//	if (!png_ptr)
//	{
//		nlwarning("couldn't save PNG image.");
//		return false;
//	}
//
//	// create info structure
//	png_info *info_ptr = png_create_info_struct(png_ptr);
//
//	if (info_ptr == NULL)
//	{
//		png_destroy_write_struct( &png_ptr, (png_info**)NULL );
//		nlwarning("couldn't save PNG image.");
//		return false;
//	}
//
//	if (setjmp(png_jmpbuf(png_ptr)))
//	{
//		png_destroy_write_struct( &png_ptr, (png_info**)NULL );
//		nlwarning("couldn't set setjmp");
//		return false;
//	}
//
//	// set the write function
//	png_set_write_fn(png_ptr, (void*)&f, writePNGData, NULL);
//
//	int iColorType;
//	
//	// only RGBA color, RGB color and gray type are implemented
//	if (d == 8)
//	{
//		iColorType = PNG_COLOR_TYPE_GRAY;
//	}
//	else if (d == 16)
//	{
//		iColorType = PNG_COLOR_TYPE_GRAY_ALPHA;
//	}
//	else if (d == 24)
//	{
//		iColorType = PNG_COLOR_TYPE_RGB;
//	}
//	else
//	{
//		iColorType = PNG_COLOR_TYPE_RGBA;
//	}
//
//	// we don't have to implement 16bits formats because NeL only uses 8bits
//	const int iBitDepth = 8;
//
//	// set correct values for PNG header
//	png_set_IHDR(png_ptr, info_ptr, _Width, _Height, iBitDepth, iColorType,
//		PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
//
//	png_color_8 sig_bit;
//
//	if (iColorType & PNG_COLOR_MASK_COLOR)
//	{
//		sig_bit.red = sig_bit.green = sig_bit.blue = (uint8)iBitDepth;
//	}
//	else
//	{
//		sig_bit.gray = (uint8)iBitDepth;
//	}
//
//	if (iColorType & PNG_COLOR_MASK_ALPHA)
//	{
//		sig_bit.alpha = (uint8)iBitDepth;
//	}
//	else
//	{
//		sig_bit.alpha = 0;
//	}
//
//	// set bit depths
//	png_set_sBIT(png_ptr, info_ptr, &sig_bit);
//
//	// Optional gamma chunk is strongly suggested if you have any guess
//	// as to the correct gamma of the image.
////	double gamma = 2.2;
////	png_set_gAMA(png_ptr, info_ptr, gamma);
//
//	// Optionally write comments into the image
////	png_text text_ptr[3];
////	text_ptr[0].key = "Title";
////	text_ptr[0].text = "Mona Lisa";
////	text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE;
////	text_ptr[1].key = "Author";
////	text_ptr[1].text = "Leonardo DaVinci";
////	text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE;
////	text_ptr[2].key = "Description";
////	text_ptr[2].text = "<long text>";
////	text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt;
//
////	png_set_text(png_ptr, info_ptr, text_ptr, 3);
//
//	// write the file header information
//	png_write_info(png_ptr, info_ptr);
//
//	// shift the pixels up to a legal bit depth
//	png_set_shift(png_ptr, &sig_bit);
//
//	// pack pixels into bytes
//	png_set_packing(png_ptr);
//
//	// rowbytes is the width x number of channels
//	uint32 rowbytes = (uint32)png_get_rowbytes(png_ptr, info_ptr);
//	uint32 dstChannels = png_get_channels(png_ptr, info_ptr);
//
//	// get channels number of bitmap
//	sint srcChannels = bitPerPixels[PixelFormat]/8;
//
//	// get size of bitmap
//	sint height = _Height;
//	sint width = _Width;
//
//	// allocates buffer to copy image data
//	png_bytepp row_pointers = (png_bytepp)png_malloc(png_ptr, height * sizeof(png_bytep));
//
//	for (sint row = 0; row < height; row++)
//		row_pointers[row] = (png_bytep)png_malloc(png_ptr, rowbytes);
//
//	sint y, x, i;
//
//	for(y=0; y<height; ++y)
//	{
//		for(x=0; x<width; ++x)
//		{
//			const uint srcOffset = y*width*srcChannels + x*srcChannels;
//			const uint dstOffset = x*dstChannels;
//
//			if (dstChannels <= 2 && srcChannels == 4)
//			{
//				// convert colors to gray
//				row_pointers[y][dstOffset] = CRGBA(_Data[0][srcOffset+0],
//					_Data[0][srcOffset+1], _Data[0][srcOffset+2]).toGray();
//
//				if (sig_bit.alpha)
//				{
//					// copy alpha value
//					row_pointers[y][dstOffset+1] = _Data[0][srcOffset+3];
//				}
//			}
//			else if (dstChannels >= 3 && srcChannels <= 2)
//			{
//				// convert gray to colors
//				for(i=0; i<3; ++i)
//				{
//					row_pointers[y][dstOffset+i] = _Data[0][srcOffset];
//				}
//
//				if (sig_bit.alpha)
//				{
//					// copy alpha value
//					row_pointers[y][dstOffset+3] = PixelFormat ==
//						Luminance ? 255:_Data[0][srcOffset+1];
//				}
//			}
//			else
//			{
//				// copy all values
//				for(i=0; i<(sint)dstChannels; ++i)
//				{
//					row_pointers[y][dstOffset+i] = _Data[0][srcOffset+i];
//				}
//			}
//		}
//	}
//
//	// writing image data
//	png_write_image(png_ptr, row_pointers);
//
//	// writing the rest of the file
//	png_write_end(png_ptr, info_ptr);
//
//	// free allocated memory to copy each rows
//	for (sint row = 0; row < height; row++)
//		png_free(png_ptr, row_pointers[row]);
//
//	// free allocated memory to copy the image
//	png_free(png_ptr, row_pointers);
//
//	// clean up after the write, and free any memory allocated
//	png_destroy_write_struct(&png_ptr, &info_ptr);
//
//	return true;
//}
//
//}//namespace
